package com.gxa.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.gxa.common.R;
import com.gxa.common.Status;
import com.gxa.common.exception.ValidateAppointmentSettingVoException;
import com.gxa.common.vo.AppointmentPageRequest;
import com.gxa.common.vo.AppointmentSettingVo;
import com.gxa.entity.SysReservationSet;
import com.gxa.entity.SysUser;
import com.gxa.mapper.AppointmentManagementMapper;
import com.gxa.mapper.AppointmentSettingMapper;
import com.gxa.mapper.SysUserMapper;
import com.gxa.service.AppointmentService;
import com.gxa.utils.ValidateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

import static com.gxa.common.Status.*;

/**
 * @author MacieSerenity
 */
@Service
public class AppointmentSettingServiceImpl implements AppointmentService {

    @Autowired
    AppointmentSettingMapper appointmentSettingMapper;

    @Autowired
    AppointmentManagementMapper appointmentManagementMapper;

    @Autowired
    SysUserMapper sysUserMapper;

    /**
     * 最大的页面大小
     */
    private static final int MAX_PAGE_SIZE = 50;
    /**
     * 最小的页面
     */
    private static final int LEAST_PAGE_NUM = 1;

    @Override
    public R findAppointmentUserList(AppointmentPageRequest appointmentPageRequest) {
        //判断是否有筛选条件，有的话调不同的方法
        R result = new R();
        Integer tPageSize = 20;
        Integer tPageNum = 1;
        List<SysReservationSet> allSysReservation = null;
        PageInfo<SysReservationSet> page = null;
        Integer total = 0;
        //判断是否有查询条件对象
        if (appointmentPageRequest != null) {
            //有这个查询对象就对查询条件进行验证，查看条件是否
            //查看页数和大小是否合格，如果没有这两个，或者其中一个为空则直接返回
            if (appointmentPageRequest.getPageNum() != null && appointmentPageRequest.getPageSize() != null) {
                //如果页数小于1，大小大于50，不符合规范
                if (appointmentPageRequest.getPageNum() < LEAST_PAGE_NUM || appointmentPageRequest.getPageSize() > MAX_PAGE_SIZE) {
                    return result.fromStatus(Status.BAD_PAGE_PARAM);
                }
                tPageSize = appointmentPageRequest.getPageSize();
                tPageNum = appointmentPageRequest.getPageNum();
            }
            //检查是否有查询条件
            if (appointmentPageRequest.getQuery() != null && !"".equals(appointmentPageRequest.getQuery())) {
                //有查询条件进行模糊查询
                allSysReservation = findAppointmentListWIthQuery(appointmentPageRequest);
                total = getListByQueryCount(appointmentPageRequest.getQuery());
            } else {
                //没有查询条件，直接查询返回默认
                allSysReservation = findAppointmentListWithOutQuery(tPageNum, tPageSize);
                total = getListCount();
            }
        } else {
            //没有查询对象，默认返回第一页20条
            allSysReservation = findAppointmentListWithOutQuery(tPageNum, tPageSize);
            total = getListCount();
        }
        //初始page
        page = new PageInfo<>(allSysReservation);
        //set Total
        page.setTotal(total);
        result.fromStatus(Status.SUCCESS);
        result.setData(page);
        return result;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public R addAppointmentUser(AppointmentSettingVo appointmentSettingVo) {
        //先对信息进行验证
        try {
            ValidateUtils.validateAppointmentSettingVo(appointmentSettingVo, false, true);
            R r = validateUser(appointmentSettingVo.getUserId());
            if (r.getCode() == 200) {
                //说明有这个医生，且这个医生没有添加过预约设置的信息 且 该医生的状态是 有效，那就可以添加
                Integer integer = appointmentSettingMapper.insertAppointmentSetting(appointmentSettingVo);
                if (integer > 0) {
                    return R.ok();
                } else {
                    //只能是插入数据的时候有错误，如果发生了错误会被捕获并回滚
                    return R.failure(Status.SYSTEM_ERROR);
                }
            } else {
                //说明该医生可能是无效的或者其它状态（被删除）等
                return r;
            }
        } catch (ValidateAppointmentSettingVoException e) {
            throw new RuntimeException("信息验证失败，因为：" + e.getMessage());
        }
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public R updateAppointmentUser(AppointmentSettingVo appointmentSettingVo) {
        try {
            //先进行数据验证
            ValidateUtils.validateAppointmentSettingVo(appointmentSettingVo, true, false);
            /**
             *说明有这个医生，且这个医生没有预约设置的信息  且 该医生的状态是 有效，那就可以修改
             *只允许更改天数和人数（且已预约的只算人数，天数更改只对后面添加的数据限制）
             *该医生还有预约信息就不允许删除更新也只能更新更大的容量，如果小于当前人数，报错
             */
            //获取该医生已经拥有的预约数量（不能低于这个数量）
//            Integer nowNumber = appointmentSettingMapper.getAppointmentNowNumberByUserId(appointmentSettingVo.getUserId());
            SysReservationSet appointmentById = appointmentSettingMapper.getAppointmentById(appointmentSettingVo.getId());
            Integer nowNumber = appointmentById.getNowNumber();
            if (nowNumber != null) {
                //验证数据是否符合规范
                if (nowNumber > appointmentSettingVo.getNumberLimit()) {
                    return R.failure("不允许比当前预约数量还要低！目前已经预约的人数" + nowNumber);
                }
                //最后才修改
                Integer integer = appointmentSettingMapper.updateSysReservationById(appointmentSettingVo, new Date());
                if (integer > 0) {
                    return R.ok();
                } else {
                    return R.failure(Status.SYSTEM_ERROR);
                }
            } else {
                return R.failure("没有该医生所关联的预约信息，无法修改");
            }
        } catch (ValidateAppointmentSettingVoException e) {
            throw new RuntimeException("信息验证失败，因为：" + e.getMessage());
        }
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public R deleteAppointmentSettingById(Integer id) {
        if (id == null) {
            return R.failure(BAD_REQUEST_PARAM);
        }
        //判断该医生是否有还有预约信息，如果没有才能删除
        SysReservationSet appointmentByUserId = appointmentSettingMapper.getAppointmentById(id);
        if (appointmentByUserId == null) {
            return R.failure("未删除任何数据，这条数据不翼而飞了");
        }
        if (appointmentByUserId.getNowNumber() > 0) {
            return R.failure("该医生还有预约未处理，无法删除");
        }
        //删除之后不允许新增，旧数据依然可用
        Integer integer = appointmentSettingMapper.deleteSysReservationById(id);
        if (integer == 0) {
            return R.failure("未删除任何数据，这条数据不翼而飞了");
        }
        return R.ok();
    }

    /**
     * 根据userID查是否有这个用户，如果有，则继续查这个用户是否已经有预约设置信息，没有就返回null，有就直接返回R，返回错误信息
     *
     * @param userId 用户ID，用于查询
     * @return 结果信息
     */
    private R validateUser(Integer userId) {
        //如果没有这个用户（或者是否失效）
        if (!haveThisUser(userId)) {
            return R.failure(DONT_HAVE_THIS_USER);
        }
        //一个医生(负责人必须只能有一个预约申请），查看是否有相同的医生
        if (doesThisUserHaveReservation(userId)) {
            //如果已经有预约了，返回错误
            return R.failure(ALREADY_HAVE_APPOINTMENT);
        }
        //没有问题，返回成功
        return R.ok();
    }

    /**
     * 验证当前这个User是否存在，若存在则返回true
     *
     * @param userId User的ID
     * @return 是否存在且有效，true可用，false不可用
     */
    private boolean haveThisUser(Integer userId) {
        //验证成功之后，是否有这个医生，如果没有这个医生，返回错误
        SysUser userById = sysUserMapper.getUserById(userId);
        //若没有这个用户（被删除了），返回不可用
        if (userById == null) {
            return false;
        }
        //医生状态为失效，则返回不可用
        if (userById.getStatus() == 1) {
            return false;
        }
        //没有其他情况的话，应该是可用的
        return true;
    }

    /**
     * 查看当前User下是否有预约设置信息
     *
     * @param userId 用户的ID
     * @return 是否有这条信息
     */
    private boolean doesThisUserHaveReservation(Integer userId) {
        Integer sysReservationCountByUserId = appointmentSettingMapper.getSysReservationCountByUserId(userId);
        if (sysReservationCountByUserId == 0) {
            return false;
        }
        return true;
    }

    /**
     * 根据条件继续进行查询
     *
     * @param appointmentPageRequest 所有的查询条件
     * @return R
     */
    private List<SysReservationSet> findAppointmentListWIthQuery(AppointmentPageRequest appointmentPageRequest) {
        PageHelper.startPage(appointmentPageRequest.getPageNum(), appointmentPageRequest.getPageSize());
        List<SysReservationSet> allSysReservationByQuery = appointmentSettingMapper.findAllSysReservationByQuery(appointmentPageRequest.getQuery());
        return allSysReservationByQuery;
    }

    /**
     * 没有条件的查询
     *
     * @param tPageNum  页数
     * @param tPageSize 大小
     * @return 返回一页预约设置信息的数据
     */
    private List<SysReservationSet> findAppointmentListWithOutQuery(Integer tPageNum, Integer tPageSize) {
        //验证pageSize和pageNum是否合格
        PageHelper.startPage(tPageNum, tPageSize);
        List<SysReservationSet> allSysReservation = appointmentSettingMapper.findAllSysReservation();
        return allSysReservation;
    }

    /**
     * 获取总的大小（不使用条件的情况下）
     *
     * @return 条目的总数
     */
    private Integer getListCount() {
        return appointmentSettingMapper.getAllActiveReservationCount();
    }

    /**
     * 获取条件筛选之后返回的总数大小
     *
     * @return 条目大小
     */
    private Integer getListByQueryCount(String query) {
        return appointmentSettingMapper.getAllActiveReservationWithQueryCount(query);
    }
}
